import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.io.*;
import javax.sound.sampled.*;

class Speak extends Frame implements ActionListener
{
 Button start,stop,play;
 Font f1;
 SourceDataLine sdl;
 TargetDataLine tdl;
 Mixer mix;
 Recorder rec;
 boolean recording,playing;
 Port m_port,h_port,s_port;
 byte[] collected_data;
 AudioPermission ap;
 int total_bytes;

 Speak()
	{
	 super("SpeakAndListen");
	 this.setSize(400,400);
	 this.setVisible(true);
	 this.setLayout(null);

	 f1=new Font("Lucida Calligraphy",Font.BOLD,80);

	 recording=playing=false;
	
  	 start=new Button("Start");
	 stop=new Button("Stop");
	 stop.setEnabled(false);
	 play=new Button("Play");
	 play.setEnabled(false);

 	 start.setBounds(580,400,80,30);
	 stop.setBounds(670,400,80,30);
	 play.setBounds(760,400,80,30);

	 add(start);
	 add(stop);
	 add(play);

 	 start.addActionListener(this);
	 stop.addActionListener(this);
	 play.addActionListener(this);

	 M_W_Adapter adapter=new M_W_Adapter(this);
	 addWindowListener(adapter);
	}

 public void actionPerformed(ActionEvent ae)
	{
	 String c_name=ae.getActionCommand();
	 if(c_name.equals("Start"))
		{
		 play.setEnabled(false);	
		 start.setEnabled(false);
		 stop.setEnabled(true);	

		 recording=true;
		 playing=false;

		 this.getTargetDataLine();
		 rec=new Recorder(tdl);
		 rec.start();
		}
	 else if(c_name.equals("Stop"))
		{
		 if(recording)
			{
			 rec.stopRecording();
			}
		 else
			{
			 sdl.close();
			}
		 stop.setEnabled(false);
		 start.setEnabled(true);	
		 play.setEnabled(true);
		 
		}
	 else
		{
		 stop.setEnabled(true);
		 start.setEnabled(false);
		 play.setEnabled(false);
		 
		 playing=true;
		 recording=false;
		
		int	EXTERNAL_BUFFER_SIZE = 128000;
		File file = new File ("RecordedFile");
		byte[]	abData = new byte[EXTERNAL_BUFFER_SIZE];
		AudioInputStream	audioInputStream = null;
		try
		{
			audioInputStream = AudioSystem.getAudioInputStream(file);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		AudioFormat	sourceFormat = audioInputStream.getFormat();
		AudioFormat.Encoding	targetEncoding = AudioFormat.Encoding.PCM_SIGNED;
		audioInputStream = AudioSystem.getAudioInputStream(targetEncoding, audioInputStream);
		AudioFormat	audioFormat = audioInputStream.getFormat();

		this.getSourceDataLine();
		sdl.start();
		int	nBytesRead = 0;
		while (nBytesRead != -1)
		{
			try
			{
				nBytesRead = audioInputStream.read(abData, 0, abData.length);
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
			if (nBytesRead >= 0)
			{
				int	nBytesWritten = sdl.write(abData, 0, nBytesRead);
			}
		}
		sdl.close();
		}
	}

 public void getTargetDataLine()
	{
	 AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100.0F, 16, 2, 4, 44100.0F, false);
	 DataLine.Info	info = new DataLine.Info(TargetDataLine.class, audioFormat,65536);
	 try
		{
		 Mixer.Info[] fos = AudioSystem.getMixerInfo();
		 mix = AudioSystem.getMixer(fos[3]);
		 tdl= (TargetDataLine) mix.getLine(info);
		 tdl.open(audioFormat,65536);
		}
		catch (LineUnavailableException e)
		{
			 e.printStackTrace(); 
		}
		catch (Exception e)
		{
			e.printStackTrace(); 
		}
	}

 public void getSourceDataLine()
	{
	 AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100.0F, 16, 2, 4, 44100.0F, false);
	 DataLine.Info	info = new DataLine.Info(SourceDataLine.class, audioFormat,65536);
	 try
		{
		 Mixer.Info[] fos = AudioSystem.getMixerInfo();
		 mix = AudioSystem.getMixer(fos[0]);
		 sdl= (SourceDataLine) mix.getLine(info);
		 sdl.open(audioFormat,65536);
		}
		catch (LineUnavailableException e)
		{
			 e.printStackTrace(); 
		}
		catch (Exception e)
		{
			e.printStackTrace(); 
		}
	}
 public static void main(String s[])
	{
	 Speak ss=new Speak();
	}

  public void paint(Graphics g)
	{
	 g.setFont(f1);
	 g.drawString("Speak And Listen",170,130);
	}
}

class M_W_Adapter extends WindowAdapter
{
 Speak slw;
 public M_W_Adapter(Speak sl)
	{
	 slw=sl;
	}
 public void windowClosing(WindowEvent we)
	{
	 slw.setVisible(false);
	}
}